<!doctype html>
<html>

<head>
    <title>Socket.IO chat</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font: 13px Helvetica, Arial;
        }
        
        form {
            background: #000;
            padding: 3px;
            position: fixed;
            bottom: 0;
            width: 100%;
        }
        
        form input {
            border: 0;
            padding: 10px;
            width: 90%;
            margin-right: 0.5%;
        }
        
        form button {
            width: 9%;
            background: rgb(130, 224, 255);
            border: none;
            padding: 10px;
        }
        
        #messages {
            list-style-type: none;
            margin: 0;
            padding: 0;
        }
        
        #messages li {
            padding: 5px 10px;
        }
        
        #messages li:nth-child(odd) {
            background: #eee;
        }
        
        #typing {
            color: #eee;
            margin-bottom: 5px;
            display: block;
        }
    </style>
</head>

<body>
    <ul id="messages"></ul>
    <form action="">
        <p id="typing">Someone's typing...</p>
        <input id="m" autocomplete="off" /><button>Send</button>
    </form>

    <script src="/socket.io/socket.io.js"></script>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script>
        var socket = io();
        // Hide no one's typing by default
        $('#typing').hide();

        // Send typing actions...
        // The Document method querySelector() returns the first Element within the document
        // that matches the specified selector, or group of selectors.
        // If no matches are found, null is returned.
        const input = document.querySelector('input');
        input.addEventListener('input', (i) => {
            socket.emit('typing', i.data);
        });

        // Listen who's typing
        socket.on('typing', function(id) {
            $('#typing').show();
            $('#typing').text(id + ' is typing...');
            setTimeout(async function() {
                $('#typing').hide();
            }, 5000);
        });

        // Send message
        $('form').submit(function(e) {
            e.preventDefault(); // prevents page reloading

            // Return if empty message
            if ($('#m').val() == "") return;

            // Broadcast message
            socket.emit('send_message', JSON.stringify({
                'uuid': uuidv4(),
                'message': $('#m').val(),
            }));
            $('#m').val('');
            return false;
        });

        // Receive message
        socket.on('receive_message', function(data) {
            const message = JSON.parse(data)
            $('#messages').append($('<li>').text(message['message']));
        });

        function uuidv4() {
            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                var r = Math.random() * 16 | 0,
                    v = c == 'x' ? r : (r & 0x3 | 0x8);
                return v.toString(16);
            });
        }
    </script>
</body>

</html>